package cn.com.idmy.cloud.config;

import cn.com.idmy.base.config.DefaultConfig;
import cn.com.idmy.cloud.exception.CloudException;
import cn.com.idmy.cloud.util.WebUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONException;
import feign.Feign;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import feign.Response;
import feign.codec.ErrorDecoder;
import feign.codec.ErrorDecoder.Default;
import lombok.RequiredArgsConstructor;
import org.dromara.hutool.core.data.id.IdUtil;
import org.dromara.hutool.core.io.IoUtil;
import org.jetbrains.annotations.NotNull;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.cloud.openfeign.support.SpringMvcContract;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Lazy;

import java.util.List;

@RequiredArgsConstructor
public class GlobalFeignConfig implements RequestInterceptor {

    @Override
    public void apply(@NotNull RequestTemplate template) {
        template.header(DefaultConfig.feignHeaderName, "true");
        template.header(DefaultConfig.spanIdHeaderName, IdUtil.fastSimpleUUID());
        template.header(DefaultConfig.requestIdHeaderName, IdUtil.fastSimpleUUID());
        var request = WebUtil.request();
        if (request != null) {
            template.header("Authorization", request.getHeader("Authorization"));
            template.header(DefaultConfig.tenantIdHeaderName, request.getHeader(DefaultConfig.tenantIdHeaderName));
            template.header(DefaultConfig.traceIdHeaderName, request.getHeader(DefaultConfig.traceIdHeaderName));
            template.header(DefaultConfig.corsDisabledHeaderName, request.getHeader(DefaultConfig.corsDisabledHeaderName));
        }
    }

    @Bean
    @NotNull
    @Lazy
    @DependsOn("fastJsonHttpMessageConverter")
    public Feign.Builder feignBuilder(ErrorDecoder errorDecoder, List<RequestInterceptor> requestInterceptors, HttpMessageConverters converters) {
        return Feign.builder()
                .encoder(new SpringEncoder(() -> converters))
                .decoder(new SpringDecoder(() -> converters))
                .errorDecoder(errorDecoder)
                .requestInterceptors(requestInterceptors)
                .contract(new SpringMvcContract());
    }

    @Bean
    @NotNull
    @Lazy
    public ErrorDecoder errorDecoder() {
        return GlobalFeignConfig::decode;
    }

    private static Exception decode(String key, Response response) {
        if (response.status() == 200) {
            return new Default().decode(key, response);
        } else {
            if (response.body() == null) {
                throw new CloudException(response.status(), response.request().url());
            }
            String json;
            try {
                json = IoUtil.readUtf8(response.body().asInputStream());
            } catch (Exception e) {
                throw new CloudException(response.status(), e.getMessage());
            }

            try {
                var out = JSON.parseObject(json);
                var code = out.getInteger("code");
                var msg = out.getString("msg");
                if (code == null) {
                    code = out.getInteger("status");
                    if (code != null) {
                        msg = out.getString("detail");
                    }
                }
                if (code == null) {
                    code = -1;
                }
                throw new CloudException(code, msg);
            } catch (JSONException e) {
                throw new CloudException(response.status(), json);
            }
        }
    }
}
